﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;

namespace Framework.AssetsManager
{
    public class RM : Singleton<RM> {

        public Object GetResource(string _name)
        {
#if NO_UPDATE
            Object o = Resources.Load(RemoveExt (_name));
            return o;

#else
            UnityEngine.Object o = ResManager.Instance.GetResource(_name);

            if (o != null)
                return o;
            else
            {
                AssetData data = AssetDataManager.Instance.GetAssetData(_name);
                if (data == null)
                {
                    Debug.LogError("RM.GetResource, Asset Data is null,:" + _name);
                }
                else
                {
                    return GetResourceFromAssetData(data);
                }
            }

            return null;
#endif
        }

        public T GetSubAssetInResource<T>(string name, string subAssetName) where T: Object
        {
#if NO_UPDATE
            T[] assets = Resources.LoadAll<T>(RemoveExt(name)); 
            for(int i = 0; i < assets.Length; i++)
            {
                if (assets[i].name == subAssetName)
                    return assets[i];
            }
            return null;
#else
            string assetName = subAssetName + "@" + name;
            T o = ResManager.Instance.GetResource(assetName) as T;

            if (o != null)
                return o;
            else
            {
                AssetData data = AssetDataManager.Instance.GetAssetData(name);
                if (data == null)
                {
                    Debug.LogError("RM.GetResource, Asset Data is null,:" + name);
                }
                else
                {
                    return GetResourceFromAssetData<T>(data, subAssetName);
                }
            }

            return null;
#endif
        }

        private string RemoveExt(string _path)
        {
            int index = _path.LastIndexOf(".");

            if (index > -1)
            {
                return _path.Substring(0, index);
            }
            else
                return _path;
        }

        private string GetFileName(string _path)
        {
            int index = _path.LastIndexOf("/");

            if (index > -1)
            {
                return _path.Substring(index + 1);
            }
            else
            {
                return _path;
            }
        }

        public void RemoveResource(string _name)
        {
            ResManager.Instance.RemoveResource(_name);
        }

        public void Clear(string _name)
        {
            ResManager.Instance.Clear(_name);
        }

        public void Clear(EResType _type)
        {
            ResManager.Instance.Clear(_type);
        }

        public void Clear()
        {
            ResManager.Instance.Clear();
        }

        public static string StreamingAssetsDir
        {
            get
            {
#if UNITY_ANDROID && !UNITY_EDITOR
                return Application.dataPath+"!assets";
#else
                return Application.streamingAssetsPath;
#endif
            }
        }
         
        Object GetResourceFromAssetData(AssetData data)
        {
            if (data.type == EResType.ASSETBUNDLE)
            {
                AssetBundle bundle = LoadAsset(data);
                Object asset = bundle.LoadAsset(GetFileName(data.name));
                ResManager.Instance.AddResource(data.name, data.type, asset);
                return asset;
            }
            else if (data.type == EResType.AB_MANIFEST)
            {
                AssetBundle bundle = LoadAssetNoDepn(data);
                Object asset = bundle.LoadAsset(data.name);
                ResManager.Instance.AddResource(data.name, data.type, asset);
                return asset;
            }
            else if(data.type == EResType.NORMAL)
            {
                return Resources.Load(data.path);
            }
            else
            {
                Debug.LogError("Unknow Load Type");
            }
            return null;
        }

        T GetResourceFromAssetData<T>(AssetData data, string subAssetName) where T: Object
        {
            T assetOfName = null;
            if (data.type == EResType.ASSETBUNDLE)
            {
                AssetBundle bundle = LoadAsset(data);
                Object[] assets = null;
                assets = bundle.LoadAssetWithSubAssets(GetFileName(data.name), typeof(T));
                for (int i = 0; i < assets.Length; i++)
                {
                    ResManager.Instance.AddResource(assets[i].name + "@" + data.name, data.type, assets[i]);
                    if (subAssetName == assets[i].name)
                        assetOfName = (T)assets[i];
                }
            }
            else if (data.type == EResType.NORMAL)
            {
                T[] assets = Resources.LoadAll<T>(data.path);
                for (int i = 0; i < assets.Length; i++)
                {
                    ResManager.Instance.AddResource(assets[i].name + "@" + data.name, data.type, assets[i]);
                    if (subAssetName == assets[i].name)
                        assetOfName = assets[i];
                }
            }
            else
            {
                Debug.LogError("Unknow Load Type");
            }

            return assetOfName;
        }

        public AssetBundle LoadAssetNoDepn(AssetData data)
        {
            AssetData bundleAssetData = AssetDataManager.Instance.GetAssetData(data.path);
            AssetBundle bundle = LoadAssetBundle(bundleAssetData);

            return bundle;
        }

        private AssetBundle LoadAsset(AssetData data)
        {
            AssetData bundleAssetData = AssetDataManager.Instance.GetAssetData(data.path);
            AssetBundle bundle = ResManager.Instance.GetResource<AssetBundle>(bundleAssetData.name);
            if (bundle == null)
            {
                LoadDependencies(bundleAssetData.name);
                bundle = LoadAssetBundle(bundleAssetData);
            }
            return bundle;
        }

        private void LoadDependencies(string _ab)
        {
            AssetBundleManifest manifest = ResManager.Instance.GetResource<AssetBundleManifest>(AssetsMgtConst.Manifest);

            if (manifest == null)
            {
                Debug.LogError("Please initialize AssetBundleManifest by calling AssetBundleManager.Initialize()");
                return;
            }

            string[] dependencies = manifest.GetAllDependencies(_ab);
            if (dependencies.Length == 0) return;

            for (int i = 0; i < dependencies.Length; i++)
            {
                AssetData dependencyData = AssetDataManager.Instance.GetAssetData(dependencies[i]);
                LoadDependencies(dependencyData.name);
                LoadAssetBundle(dependencyData);
            }
        }

        AssetBundle LoadAssetBundle(AssetData data)
        {
            AssetBundle assetBundle = ResManager.Instance.GetResource<AssetBundle>(data.name);
            if (assetBundle != null)
            {
                ABCacheTimer.Instance.ResetABTime(data.name);
                return assetBundle;
            }
                
            string path;
            if (data.version == 0)
            {
                path = StreamingAssetsDir + "/update/" + data.name;
            }
            else
            {
                path = Application.persistentDataPath + "/res" + AssetsMgtConst.CurrentVersion+ "/" + data.name;
            }
            assetBundle = AssetBundle.LoadFromFile(path);
            ResManager.Instance.AddResource(data.name, EResType.ASSETBUNDLE, assetBundle);
            float cacheTime = Config.ABCacheTime;
            ABCache abCache = new ABCache(data.name, Config.ABCacheTime, assetBundle);
            ABCacheTimer.Instance.AddABCache(abCache);
            return assetBundle;
        }

    }
}
